package com.jy.project.service.imp;

import cn.hutool.Hutool;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.jy.project.domain.*;
import com.jy.project.dto.*;
import com.jy.project.domain.Apply;
import com.jy.project.domain.Material;
import com.jy.project.domain.User;
import com.jy.project.dto.MaterialDTO;
import com.jy.project.dto.MaterialQueryDTO;
import com.jy.project.dto.MaterialUpdateDTO;
import com.jy.project.dto.MatericalCopyDTO;
import com.jy.project.enums.ApplyTypeEnum;
import com.jy.project.enums.ApplyTypeMatericalEnum;
import com.jy.project.enums.RequiredTypeEnum;
import com.jy.project.ex.BizException;
import com.jy.project.mapper.*;
import com.jy.project.service.MaterialAttrValueService;
import com.jy.project.service.MaterialService;
import com.jy.project.util.CodeUtils;
import com.jy.project.util.RedisUtils;
import com.jy.project.vo.MaterialFieldValueVO;
import com.jy.project.vo.MaterialVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class MaterialServiceImpl implements MaterialService {

    @Autowired
    private MaterialMapper materialMapper;

    @Autowired
    private MaterialAttrFieldMapper materialAttrFieldMapper;

    @Autowired
    private MaterialAttrValueMapper materialAttrValueMapper;

    @Autowired
    private MaterialAttrValueService materialAttrValueService;


    @Autowired
    private UserMapper userMapper;

    @Value("${request_url}")
    private String requestUrl;


    @Autowired
    private ApplyMapper applyMapper;

    @Autowired
    private RedisUtils redisUtils;


    private static final String DEFAULT_QUALITYSTATUS = "[\"1\",\"2\",\"3\",\"4\"]";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insertMaterialDTO(MaterialDTO dto) {
        String key = DigestUtil.md5Hex(dto.toString());
        boolean bl = redisUtils.setNX(key, 1, 10);
        if (!bl){
            throw new BizException("请勿重复提交");
        }
        Material m = new Material();
        BeanUtils.copyProperties(dto, m);
        List<MaterialAttrValueDTO> attrs = dto.getAttrs() == null ? new ArrayList<>() : dto.getAttrs();
        //查询必填字段
        String assetClassNo = dto.getAssetClassNo();
        String materialNo = CodeUtils.generateMaterialNo(assetClassNo);
        MaterialAttrField example = new MaterialAttrField();
        example.setIsDelete(0);
        example.setRequired(1);
        example.setDictNo(assetClassNo);
        List<MaterialAttrField> requiredFields = materialAttrFieldMapper.select(example);
        if (!CollectionUtils.isEmpty(requiredFields)) {
            if (CollectionUtils.isEmpty(attrs)) {
                throw new BizException("有必填字段未填写");
            }
            Map<Long, String> fieldIdValueMap = attrs.stream().collect(Collectors.toMap(MaterialAttrValueDTO::getFieldId, MaterialAttrValueDTO::getFieldValue, (k1, k2) -> k1));
            for (MaterialAttrField requiredField : requiredFields) {
                Long fieldId = requiredField.getId();
                if (!fieldIdValueMap.containsKey(fieldId) || StringUtils.isBlank(fieldIdValueMap.get(fieldId))) {
                    throw new BizException(fieldId + "为必填字段");
                }
            }
        }
        //添加扩展属性
        List<MaterialAttrValue> materialAttrValueList = attrs.stream().map(attrValue -> {
            MaterialAttrValue materialAttrValue = new MaterialAttrValue();
            return materialAttrValue.setMaterialNo(materialNo).setFieldId(attrValue.getFieldId()).setFieldValue(attrValue.getFieldValue());
        }).collect(Collectors.toList());
        materialAttrValueService.insertBatch(materialAttrValueList);


        if(StringUtils.isNotEmpty(m.getUseCompanyNo())){
            if (!m.getUseCompanyNo().equals(m.getManagementCompanyNo())) {
                throw new BizException("使用公司与管理公司保持一致");
            }
        }
        m.setQualityStatus(DEFAULT_QUALITYSTATUS);
        if (StringUtils.isNotEmpty(dto.getBusinessDay())) {
            m.setBusinessDay(DateUtil.parseDate(dto.getBusinessDay()));
        }
        if (StringUtils.isNotEmpty(dto.getBuyDay())) {
            m.setBuyDay(DateUtil.parseDate(dto.getBuyDay()));
        }
        m.setMaterialNo(materialNo);
        //确定使用人的时候 需要进行审批
        Long useUserId = m.getUseUserId();
        //申请人
        Long createUserId = dto.getCreateUserId();
        if (useUserId == null) {
            User createUser = userMapper.selectByPrimaryKey(createUserId);
            //如果管理员不是自己,这
            Apply apply = new Apply();
            apply.setApplyNo(CodeUtils.generateApplyNo(ApplyTypeMatericalEnum.INSERT_MATERIAL.getValue()));
            apply.setStatus(0);
            apply.setIsDelete(0);
            Date date = new Date();
            apply.setMaterialName(dto.getName());
            apply.setMaterialNo(m.getMaterialNo());
            apply.setCreateAt(date);
            apply.setUpdateAt(date);
            apply.setUpdateDay(date);
            apply.setApplyType(ApplyTypeEnum.INSERT_MATERIAL.getCode());
            apply.setName(ApplyTypeEnum.INSERT_MATERIAL.getValue());
            apply.setApplicantCompanyNo(createUser.getCompanyNo());
            apply.setApplicantCompanyName(createUser.getCompanyName());
            apply.setApplicantDeptNo(createUser.getDeptNo());
            apply.setApplicantDeptName(createUser.getDeptName());
            apply.setApplicantUserId(createUser.getId());
            apply.setApplicantUserNickName(createUser.getNickName());
            apply.setUseCompanyNo("");
            apply.setUseCompanyName("");
            apply.setUseDeptNo("");
            apply.setUseDeptName("");
            apply.setUseUserId(null);
            apply.setUseNickName("");
            apply.setPlanningType(m.getPlanningType());
            apply.setManagementUserId(m.getManagementUserId());
            apply.setRemarks(m.getRemarks());
            applyMapper.insertSelective(apply);
            m.setStatus(1);
            return insertMaterial(m);
        }
        if (useUserId != null) {
            User user = userMapper.selectByPrimaryKey(useUserId);
            User createUser = userMapper.selectByPrimaryKey(createUserId);
            Apply apply = new Apply();
            apply.setApplyNo(CodeUtils.generateApplyNo(ApplyTypeMatericalEnum.INSERT_MATERIAL.getValue()));
            apply.setStatus(0);
            apply.setIsDelete(0);
            Date date = new Date();
            apply.setMaterialName(dto.getName());
            apply.setMaterialNo(m.getMaterialNo());
            apply.setCreateAt(date);
            apply.setUpdateAt(date);
            apply.setUpdateDay(date);
            apply.setApplyType(ApplyTypeEnum.INSERT_MATERIAL.getCode());
            apply.setName(ApplyTypeEnum.INSERT_MATERIAL.getValue());
            apply.setApplicantCompanyNo(createUser.getCompanyNo());
            apply.setApplicantCompanyName(createUser.getCompanyName());
            apply.setApplicantDeptNo(createUser.getDeptNo());
            apply.setApplicantDeptName(createUser.getDeptName());
            apply.setApplicantUserId(createUser.getId());
            apply.setApplicantUserNickName(createUser.getNickName());
            apply.setUseCompanyNo(user.getCompanyNo());
            apply.setUseCompanyName(user.getCompanyName());
            apply.setUseDeptNo(user.getDeptNo());
            apply.setUseDeptName(user.getDeptName());
            apply.setUseUserId(user.getId());
            apply.setUseNickName(user.getNickName());
            apply.setPlanningType(m.getPlanningType());
            apply.setManagementUserId(m.getManagementUserId());
            apply.setRemarks(m.getRemarks());
            applyMapper.insertSelective(apply);
            //进入审批状态为 1
            m.setStatus(1);
            return insertMaterial(m);

        }
        //如果没有填写使用人,且管理员是自己直接入库
        Long managementUserId = dto.getManagementUserId();
        if (managementUserId==createUserId){
            User user = userMapper.selectByPrimaryKey(useUserId);
            User createUser = userMapper.selectByPrimaryKey(createUserId);
            //如果管理员不是自己,这
            Apply apply = new Apply();
            apply.setApplyNo(CodeUtils.generateApplyNo(ApplyTypeMatericalEnum.INSERT_MATERIAL.getValue()));
            apply.setStatus(0);
            apply.setIsDelete(0);
            Date date = new Date();
            apply.setMaterialName(dto.getName());
            apply.setMaterialNo(m.getMaterialNo());
            apply.setCreateAt(date);
            apply.setUpdateAt(date);
            apply.setUpdateDay(date);
            apply.setApplyType(ApplyTypeEnum.INSERT_MATERIAL.getCode());
            apply.setName(ApplyTypeEnum.INSERT_MATERIAL.getValue());
            apply.setApplicantCompanyNo(createUser.getCompanyNo());
            apply.setApplicantCompanyName(createUser.getCompanyName());
            apply.setApplicantDeptNo(createUser.getDeptNo());
            apply.setApplicantDeptName(createUser.getDeptName());
            apply.setApplicantUserId(createUser.getId());
            apply.setApplicantUserNickName(createUser.getNickName());
            apply.setUseCompanyNo(user.getCompanyNo());
            apply.setUseCompanyName(user.getCompanyName());
            apply.setUseDeptNo(user.getDeptNo());
            apply.setUseDeptName(user.getDeptName());
            apply.setUseUserId(user.getId());
            apply.setUseNickName(user.getNickName());
            apply.setPlanningType(m.getPlanningType());
            apply.setManagementUserId(m.getManagementUserId());
            apply.setRemarks(m.getRemarks());
            applyMapper.insertSelective(apply);
            m.setStatus(1);
            return insertMaterial(m);
        }
        throw  new BizException("操作类型选择错误");
    }

    @Override
    public List<MaterialVO> listMaterialVO(MaterialQueryDTO dto) {
        PageHelper.startPage(dto);
        return materialMapper.listMaterialVO(dto);
    }

    @Override
    public List<MaterialVO> listNotUsedMaterialVO(MaterialQueryDTO dto) {
        dto.setUseStatus(0);
        dto.setStatus(0);
        return this.listMaterialVO(dto);
    }

    @Override
    public List<MaterialVO> listUsedMaterialVO(MaterialQueryDTO dto) {
        dto.setUseStatus(1);
        return this.listMaterialVO(dto);
    }

    @Override
    public List<MaterialVO> listUserMaterialVO(MaterialQueryDTO dto) {
        Long useUserId = dto.getUseUserId();
        if (useUserId == null) {
            return new ArrayList<>();
        }
        return this.listMaterialVO(dto);
    }

    @Override
    public MaterialVO getMaterialVO(String materialNo) {
        if (StringUtils.isEmpty(materialNo)) {
            throw new BizException("编号不能为空");
        }
        MaterialVO materialVO = materialMapper.getMaterialVO(materialNo);
        if (materialVO == null) {
            throw new BizException("找不到该资产");
        }
        //获取拓展属性
        String assetClassNo = materialVO.getAssetClassNo();
        MaterialAttrField example = new MaterialAttrField();
        example.setIsDelete(0);
        example.setDictNo(assetClassNo);
        List<MaterialAttrField> materialAttrFields = materialAttrFieldMapper.select(example);
        if (!CollectionUtils.isEmpty(materialAttrFields)) {
            MaterialAttrValue materialAttrValueExample = new MaterialAttrValue();
            materialAttrValueExample.setMaterialNo(materialNo);
            materialAttrValueExample.setIsDelete(0);
            List<MaterialAttrValue> materialAttrValues = materialAttrValueMapper.select(materialAttrValueExample);
            Map<Long, MaterialAttrValue> fieldIdValueMap = materialAttrValues.stream().collect(Collectors.toMap(MaterialAttrValue::getFieldId, materialAttrValue -> materialAttrValue, (k1, k2) -> k1));
            //封装拓展属性
            List<MaterialFieldValueVO> attrs = new ArrayList<>();
            for (MaterialAttrField materialAttrField : materialAttrFields) {
                Long fieldId = materialAttrField.getId();
                MaterialFieldValueVO materialFieldValueVO = new MaterialFieldValueVO();
                materialFieldValueVO.setFieldId(fieldId).setFieldName(materialAttrField.getFieldName()).setRequired(materialAttrField.getRequired()).setRequiredValue(RequiredTypeEnum.getValue(materialAttrField.getRequired()));
                if (fieldIdValueMap.containsKey(fieldId)) {
                    MaterialAttrValue materialAttrValue = fieldIdValueMap.get(fieldId);
                    materialFieldValueVO.setFieldValue(StringUtils.isBlank(materialAttrValue.getFieldValue()) ? "" : materialAttrValue.getFieldValue());
                } else {
                    materialFieldValueVO.setFieldValue("");
                }
                attrs.add(materialFieldValueVO);
            }
            materialVO.setAttrs(attrs);
        }
        return materialVO;
    }

    @Override
    public boolean copy(MatericalCopyDTO dto) {
        if (StringUtils.isEmpty(dto.getMaterialNo())) {
            throw new BizException("编号不能为空");
        }
        Long num = dto.getNum();
        if (num <= 0) {
            throw new BizException("复制数量需要大于0");
        }
        Example example = new Example(Material.class);
        example.createCriteria().andEqualTo("materialNo", dto.getMaterialNo());
        Material material = materialMapper.selectOneByExample(example);
        String classNo = material.getAssetClassNo();
        List<Material> materials = new ArrayList<>();
        for (Long i = 0L; i < num; i++) {
            Material m = new Material();
            BeanUtils.copyProperties(material, m);
            m.setId(null);
            m.setMaterialNo(CodeUtils.generateMaterialNo(classNo));
            m.setIsBatch(1);
            m.setUseStatus(0);
            m.setStatus(1);
            materials.add(m);
        }
        return materialMapper.insertList(materials) > 0;
    }

    @Override
    @Transactional
    public boolean update(MaterialUpdateDTO dto) {
        String materialNo = dto.getMaterialNo();
        MaterialVO materialVO = getMaterialVO(materialNo);
        if (materialVO == null) {
            throw new BizException("没有当前数据");
        }
        Material material = new Material();
        BeanUtils.copyProperties(dto, material);
        String qualityStatus = dto.getQualityStatus();
        if (StringUtils.isNotEmpty(qualityStatus)) {
            String[] split = qualityStatus.split(",");
            material.setQualityStatus(JSONObject.toJSONString(split));
        }
        material.setIsBatch(0);
        //拓展属性处理
        List<MaterialAttrValueDTO> attrs = dto.getAttrs() == null ? new ArrayList<>() : dto.getAttrs();
        //查询必填字段
        String assetClassNo = dto.getAssetClassNo();
        MaterialAttrField example = new MaterialAttrField();
        example.setIsDelete(0);
        example.setRequired(1);
        example.setDictNo(assetClassNo);
        List<MaterialAttrField> requiredFields = materialAttrFieldMapper.select(example);
        if (!CollectionUtils.isEmpty(requiredFields)) {
            if (CollectionUtils.isEmpty(attrs)) {
                throw new BizException("有必填字段未填写");
            }
            Map<Long, String> fieldIdValueMap = attrs.stream().collect(Collectors.toMap(MaterialAttrValueDTO::getFieldId, MaterialAttrValueDTO::getFieldValue, (k1, k2) -> k1));
            for (MaterialAttrField requiredField : requiredFields) {
                Long fieldId = requiredField.getId();
                if (!fieldIdValueMap.containsKey(fieldId) || StringUtils.isBlank(fieldIdValueMap.get(fieldId))) {
                    throw new BizException(fieldId + "为必填字段");
                }
            }
        }
        for (MaterialAttrValueDTO attr : attrs) {
            //查看这个字段是否有值
            MaterialAttrValue valueExample = new MaterialAttrValue();
            valueExample.setFieldId(attr.getFieldId());
            valueExample.setMaterialNo(materialNo);
            valueExample.setIsDelete(0);
            MaterialAttrValue existAttrValue = materialAttrValueMapper.selectOne(valueExample);
            if (existAttrValue == null) {
                //属性值不存在，新增
                MaterialAttrValue materialAttrValue = new MaterialAttrValue();
                materialAttrValue.setMaterialNo(materialNo);
                materialAttrValue.setIsDelete(0);
                materialAttrValue.setCreateAt(new Date());
                materialAttrValue.setFieldId(attr.getFieldId());
                materialAttrValue.setFieldValue(attr.getFieldValue());
                materialAttrValueMapper.insertSelective(materialAttrValue);
            } else {
                //有原属性值存在，修改
                MaterialAttrValue materialAttrValue = new MaterialAttrValue();
                materialAttrValue.setFieldValue(attr.getFieldValue());
                materialAttrValue.setUpdateAt(new Date());
                materialAttrValue.setId(existAttrValue.getId());
                materialAttrValueMapper.updateByPrimaryKeySelective(materialAttrValue);
            }
        }
        material.setManagementCompanyName(null);
        material.setManagementCompanyNo(null);
        material.setUseCompanyName(null);
        material.setUseCompanyNo(null);
        material.setUseDeptName(null);
        material.setUseDeptNo(null);
        material.setUseUserId(null);
        material.setUseNickName(null);
        material.setStatus(null);
        return materialMapper.updateByPrimaryKeySelective(material) > 0;
    }

    @Override
    @Transactional
    public boolean updateReapply(MaterialUpdateDTO dto) {
        String materialNo = dto.getMaterialNo();
        MaterialVO materialVO = getMaterialVO(materialNo);
        if (materialVO == null) {
            throw new BizException("没有当前数据");
        }
        Material material = new Material();
        BeanUtils.copyProperties(dto, material);
        if (material.getUseUserId()==0){
            material.setUseUserId(null);
        }
        if (material.getManagementUserId()==0){
            material.setManagementCompanyNo(null);
        }
        material.setStatus(null);
        String qualityStatus = dto.getQualityStatus();
        if (StringUtils.isNotEmpty(qualityStatus)) {
            String[] split = qualityStatus.split(",");
            material.setQualityStatus(JSONObject.toJSONString(split));
        }
        material.setIsBatch(0);
        //拓展属性处理
        List<MaterialAttrValueDTO> attrs = dto.getAttrs() == null ? new ArrayList<>() : dto.getAttrs();
        //查询必填字段
        String assetClassNo = dto.getAssetClassNo();
        MaterialAttrField example = new MaterialAttrField();
        example.setIsDelete(0);
        example.setRequired(1);
        example.setDictNo(assetClassNo);
        List<MaterialAttrField> requiredFields = materialAttrFieldMapper.select(example);
        if (!CollectionUtils.isEmpty(requiredFields)) {
            if (CollectionUtils.isEmpty(attrs)) {
                throw new BizException("有必填字段未填写");
            }
            Map<Long, String> fieldIdValueMap = attrs.stream().collect(Collectors.toMap(MaterialAttrValueDTO::getFieldId, MaterialAttrValueDTO::getFieldValue, (k1, k2) -> k1));
            for (MaterialAttrField requiredField : requiredFields) {
                Long fieldId = requiredField.getId();
                if (!fieldIdValueMap.containsKey(fieldId) || StringUtils.isBlank(fieldIdValueMap.get(fieldId))) {
                    throw new BizException(fieldId + "为必填字段");
                }
            }
        }
        for (MaterialAttrValueDTO attr : attrs) {
            //查看这个字段是否有值
            MaterialAttrValue valueExample = new MaterialAttrValue();
            valueExample.setFieldId(attr.getFieldId());
            valueExample.setMaterialNo(materialNo);
            valueExample.setIsDelete(0);
            MaterialAttrValue existAttrValue = materialAttrValueMapper.selectOne(valueExample);
            if (existAttrValue == null) {
                //属性值不存在，新增
                MaterialAttrValue materialAttrValue = new MaterialAttrValue();
                materialAttrValue.setMaterialNo(materialNo);
                materialAttrValue.setIsDelete(0);
                materialAttrValue.setCreateAt(new Date());
                materialAttrValue.setFieldId(attr.getFieldId());
                materialAttrValue.setFieldValue(attr.getFieldValue());
                materialAttrValueMapper.insertSelective(materialAttrValue);
            } else {
                //有原属性值存在，修改
                MaterialAttrValue materialAttrValue = new MaterialAttrValue();
                materialAttrValue.setFieldValue(attr.getFieldValue());
                materialAttrValue.setUpdateAt(new Date());
                materialAttrValue.setId(existAttrValue.getId());
                materialAttrValueMapper.updateByPrimaryKeySelective(materialAttrValue);
            }
        }

        return materialMapper.updateByPrimaryKeySelective(material) > 0;
    }

    @Override
    public boolean delete(String materialNo) {
        //删除资产
        Material m = new Material();
        Date date = new Date();
        m.setUpdateDay(date);
        m.setUpdateAt(date);
        m.setIsDelete(1);
        Example example = new Example(Material.class);
        example.createCriteria().andEqualTo("materialNo", materialNo);
        return materialMapper.updateByExampleSelective(m, example) > 0;
    }

    @Override
    public boolean deletes(String[] materialNos) {
        if (materialNos == null) {
            throw new BizException("编号不能为空");
        }
        if (materialNos.length < 1) {
            throw new BizException("编号不能为空");
        }
        for (String m : materialNos) {
            this.delete(m);
        }
        return true;
    }

    @Override
    public List<MaterialVO> listMaterialVOByMaterialNos(String materialNos) {
        return materialMapper.listMaterialVOByMaterialNos(materialNos);
    }

    @Override
    public Integer countByMaterialByAssetClass(String assetClasNo) {
        return materialMapper.countByMaterialByAssetClass(assetClasNo);
    }

    @Override
    public MaterialVO getMaterialVO(ApplyDTO dto) {
        String applyNo = dto.getApplyNo();
        Apply apply = applyMapper.getApplyByApplyNo(applyNo);
        if (apply==null){
            throw new BizException("找不到此单号的申请单");
        }
        return this.getMaterialVO(apply.getMaterialNo());
    }


    private boolean insertMaterial(Material m) {
        if (m == null) {
            throw new BizException("Material对象为空");
        }
        MaterialVO materialVO = materialMapper.getMaterialVO(m.getMaterialNo());
        if (materialVO != null) {
            throw new BizException("此物资编号已经被使用");
        }
        Date date = new Date();
        m.setUpdateDay(date);
        m.setUpdateAt(date);
        m.setCreateAt(date);
        m.setRequestUrl(requestUrl + m.getMaterialNo());
        return materialMapper.insertSelective(m) > 0;
    }
}
